package com.ruoyi.service.impl;

import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.entity.JrFile;
import com.ruoyi.entity.JrFolder;
import com.ruoyi.entity.JrPermission;
import com.ruoyi.entity.vo.FolderVO;
import com.ruoyi.mapper.FilesMapper;
import com.ruoyi.mapper.FolderMapper;
import com.ruoyi.mapper.PermissionMapper;
import com.ruoyi.service.FolderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 实现步骤:
 * 1. 找到所有权限表中用户有读权限的文件夹（直接授权）。
 *
 * 2. 递归获取这些文件夹的所有子文件夹。
 *
 * 3. 过滤掉子文件夹中密级超过用户密级的。
 *
 * 4. 构建树形结构，确保只包含这些文件夹。
 */
@Service
@Slf4j
public class FolderServiceImpl implements FolderService {

    @Autowired
    private FolderMapper folderMapper;
    @Autowired
    private FilesMapper filesMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    /**
     *  权限的 文件夹树
     * @param user 用户信息
     * @return 文件夹树
     */
    public List<FolderVO> getFolderTree(SysUser user) {
        // 添加查询参数验证
        if (user.getSecurity() == null) {
            throw new IllegalArgumentException("用户密级不能为空");
        }

        System.out.println("用户id: " + user.getUserId() + " 密级 ： " + user.getSecurity());
        // 1. 获取允许的文件夹
        List<JrFolder> folders = folderMapper.selectAllowedFolders(user.getUserId(), user.getSecurity());

        // 文件数据获取
        List<JrFile> files = filesMapper.selectPermittedFilesByUserSecurity(user.getSecurity());

        // 合并数据结构
        List<FolderVO> nodes = folders.stream()
                .map(f -> new FolderVO(f.getId(), f.getParentId(), f.getName(), f.getSecurity(), "folder"))
                .collect(Collectors.toList());

        // 转换文件为树节点
        files.forEach(f -> nodes.add(
                new FolderVO(f.getId(), f.getFolderId(), f.getName(), f.getSecurity(), "file")
        ));

        // 构建树形结构
        return buildTree(nodes);
    }

    @Override
    @Transactional
    public int renameFolder(Long folderId, String newName) {
        // 1. 获取文件夹信息（需要知道它的父文件夹）
        JrFolder folder = folderMapper.selectFolderById(folderId);
        if (folder == null) {
            throw new ServiceException("文件夹不存在或已被删除");
        }

        // 2. 检查文件夹名是否包含非法字符
        if (containsInvalidChars(newName)) {
            throw new ServiceException("文件夹名包含非法字符");
        }

        // 3. 检查同一父文件夹下是否已存在同名文件夹（排除自身）
        int count = folderMapper.existsSameNameInParent(
                folder.getParentId(),
                newName,
                folderId
        );

        if (count > 0) {
            throw new ServiceException("该文件夹名已存在");
        }

        // 4. 执行重命名
        return folderMapper.renameFolder(folderId, newName);
    }

    private boolean containsInvalidChars(String name) {
        return name.contains("/") || name.contains("\\") || name.contains(":") ||
                name.contains("*") || name.contains("?") || name.contains("\"") ||
                name.contains("<") || name.contains(">") || name.contains("|");
    }

    @Override
    public int deleteFolder(Long folderId) {

        // 1. 获取文件夹信息
        JrFolder folder = folderMapper.selectFolderById(folderId);
        if (folder == null) {
            return 0;
        }

        // 2. 获取所有要删除的文件夹ID（包括子文件夹）
        List<Long> folderIds = new ArrayList<>();
        folderIds.add(folderId); // 添加自身

        // 根据祖先路径获取所有子文件夹ID
        String currentPath = folder.getAncestorPath() + folderId + "/";
        List<Long> subFolderIds = folderMapper.selectSubFolderIdsByPath(currentPath);
        folderIds.addAll(subFolderIds);

        // 3. 删除文件夹下的所有文件
        filesMapper.deleteFilesByFolderIds(folderIds);

        // 4. 删除文件夹（逻辑删除）
        return folderMapper.deleteFolderByIds(folderIds);
    }

    /**
     * 知识库文件夹树
     * @param user 用户信息
     * @return 文件夹树
     */
    public List<FolderVO> getFolderTrees(SysUser user) {
        // 添加查询参数验证
        if (user.getSecurity() == null) {
            throw new IllegalArgumentException("用户密级不能为空");
        }

        System.out.println("用户id: " + user.getUserId() + " 密级 ： " + user.getSecurity());
        // 1. 获取允许的文件夹
        List<JrFolder> folders = folderMapper.selectAllowedFolderss(user.getUserId(), user.getSecurity());

        // 文件数据获取
        List<JrFile> files = filesMapper.selectPermittedFilesByUserSecurity(user.getSecurity());

        // 合并数据结构
        List<FolderVO> nodes = folders.stream()
                .map(f -> new FolderVO(f.getId(), f.getParentId(), f.getName(), f.getSecurity(), "folder"))
                .collect(Collectors.toList());

        // 转换文件为树节点
        files.forEach(f -> nodes.add(
                new FolderVO(f.getId(), f.getFolderId(), f.getName(), f.getSecurity(), "file")
        ));

        // 构建树形结构
        return buildTree(nodes);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JrFolder createFolder(JrFolder folder) {
        // 参数校验
        validateParams(folder);

        // 生成祖先路径
        String ancestorPath = buildAncestorPath(folder.getParentId());
        folder.setAncestorPath(ancestorPath);
        folder.setFType("folder");
        folder.setIsDelete(0L);

        folderMapper.insertFolder(folder);

        // 创建物理目录
        createPhysicalFolder(ancestorPath);

        //增加权限记录
        createViewPermission(folder.getId());

        return folder;
    }
    /**
     * 创建文件夹的同时默认增加为查看权限
     * @param folderId 新创建的文件夹ID
     */
    private void createViewPermission(Long folderId) {
        System.out.println("创建文件夹的同时默认增加为查看权限       :   "+folderId);
        SysUser user = SecurityUtils.getLoginUser().getUser();
        JrPermission permission = new JrPermission();
        permission.setRefType(1); // 1=文件夹类型
        permission.setRefId(folderId);
        permission.setUserId(user.getUserId());
        permission.setCanView(true); // 设置查看权限为1
        permission.setCanDelete(false);
        permission.setCanEdit(false);
        permission.setCanAdd(false);
        permission.setCreateTime(new Date());

        permissionMapper.insertPermission(permission);
    }

    private void validateParams(JrFolder folder) {
        // 名称合法性校验
        if (StringUtils.containsWhitespace(folder.getName()) || folder.getName().contains("/")) {
            throw new IllegalArgumentException("文件夹名称包含非法字符");
        }

        // 同名校验
        if (folderMapper.existsByNameAndParentId(folder.getName(), folder.getParentId())) {
            throw new RuntimeException("当前目录已存在同名文件夹");
        }

        // 父目录存在性校验
        if (folder.getParentId() != 0 && folderMapper.selectParentById(folder.getParentId()) == null) {
            throw new RuntimeException("父目录不存在");
        }
    }

    private String buildAncestorPath(Long parentId) {
        if (parentId == 0) return "/" ;
        JrFolder parent = folderMapper.selectParentById(parentId);
        return parent.getAncestorPath() + "/";
    }

    private void createPhysicalFolder(String path) {
        File dir = new File(path);
        if (!dir.exists() && !dir.mkdirs()) {
            throw new RuntimeException("物理目录创建失败: " + path);
        }
    }

    /**
     * 构建完整的树形结构
     * @param  nodes 文件夹列表
     * @return
     */
    private List<FolderVO> buildTree(List<FolderVO> nodes) {
        // 添加ID冲突检查
        Set<Long> idSet = new HashSet<>();
        nodes.removeIf(node -> !idSet.add(node.getId()));

        Map<Long, FolderVO> nodeMap1 = nodes.stream()
                .collect(Collectors.toMap(
                        FolderVO::getId,
                        Function.identity(),
                        (existing, replacement) -> { // 合并策略
                            log.warn("合并重复节点: {} -> {}", existing.getId(), replacement.getId());
                            existing.getChildren().addAll(replacement.getChildren());
                            return existing;
                        }
                ));

        Map<Long, FolderVO> nodeMap = nodes.stream()
                .collect(Collectors.toMap(FolderVO::getId, Function.identity()));

        List<FolderVO> tree = new ArrayList<>();

        nodes.forEach(node -> {
            if (node.getParentId() == 0L) {
                tree.add(node);
            } else {
                FolderVO parent = nodeMap.get(node.getParentId());
                if (parent != null && "folder".equals(parent.getType())) {
                    parent.getChildren().add(node);
                }
            }
        });
        return tree;
    }
}
